package com.jackeysun.widget

import android.annotation.SuppressLint
import android.content.Context
import android.content.res.Resources
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.Rect
import android.os.Handler
import android.os.Looper
import android.util.AttributeSet
import android.util.Log
import android.view.View
import java.util.*
import kotlin.math.cos
import kotlin.math.sin

class ClockView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {

    private val TAG = ClockView::class.java.simpleName

    private val timeHandler = Handler(Looper.getMainLooper())

    private val runnable: Runnable by lazy {
        object : Runnable {
            override fun run() {
                rotateSecond += 6
                rotateMinute += 6f/60
                rotateHour += 30f/3600
//                Log.d(TAG, "Runnable: $rotateHour $rotateMinute $rotateSecond")
                if (rotateSecond == 360f) {
                    rotateSecond = 0f
                }
                if (rotateMinute.toInt() == 360) {
                    rotateMinute = 0f
                }
                if (rotateHour.toInt() == 360) {
                    rotateHour = 0f
                }

                if (toUpdateUI) {
                    invalidate()
                }
                timeHandler.postDelayed(this, 1000)
            }
        }
    }


    private val paintWidth = 4f.dp2px()
    private var paint = Paint().apply {
        isAntiAlias = true
        color = Color.BLACK
        strokeWidth = paintWidth
        style = Paint.Style.STROKE
    }
    private var rect: Rect? = null

    override fun onFinishInflate() {
        super.onFinishInflate()
        rotateSecond = Date().getSecond().toFloat() * 6
        rotateMinute = Date().getMinute().toFloat() * 6 + Date().getSecond().toFloat()/10
        rotateHour = Date().getHour().toFloat() * 30 + Date().getMinute().toFloat()/2

        Log.d(TAG, "onFinishInflate: $rotateHour $rotateMinute $rotateSecond")
        timeHandler.post(runnable)
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        setMeasuredDimension(measure(widthMeasureSpec), measure(heightMeasureSpec))
    }

    private fun measure(measureSpec: Int): Int {
        var result: Int
        val specMode = MeasureSpec.getMode(measureSpec)
        val specSize = MeasureSpec.getSize(measureSpec)
        if (specMode == MeasureSpec.EXACTLY) {
            result = specSize
        } else {
            result = 90f.dp2px().toInt()
            if (specMode == MeasureSpec.AT_MOST) {
                result = result.coerceAtMost(specSize)
            }
        }
        return result
    }

    @SuppressLint("DrawAllocation")
    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)
        rect = Rect(0, 0, width, height)
        canvas?.let {
            paint.apply {
                isAntiAlias = true
                color = Color.BLACK
                strokeWidth = 2f.dp2px()
                style = Paint.Style.STROKE
            }
            val mRadius = height.coerceAtMost(width).toFloat().div(2)
            it.save()
            it.translate(width.toFloat() / 2, height.toFloat() / 2)//平移
            it.drawCircle(
                0f,
                0f,
                mRadius.minus(paintWidth.div(2)),
                paint
            )
            it.restore()
            it.save()
            paint.strokeWidth = paintWidth
            paint.style = Paint.Style.STROKE
            var scaleMark: Int
            for (i in 0..59) {
                scaleMark = if (i % 5 == 0) {
                    14f.dp2px().toInt()
                } else {
                    6f.dp2px().toInt()
                }
                it.drawLine(
                    paintWidth + 2f.dp2px(),
                    height.toFloat() / 2,
                    paintWidth + scaleMark,
                    height.toFloat() / 2,
                    paint.apply { strokeWidth = 2f.dp2px() }
                )
                it.rotate(6f, width.toFloat() / 2, height.toFloat() / 2)
            }
            it.restore()
            it.save()
            val d = mRadius * 2 / 3
            paint.textSize = 42f
            paint.strokeWidth = 0.5f.dp2px()
            paint.textAlign = Paint.Align.CENTER
            val fontMetrics = paint.fontMetrics
            val top = fontMetrics.top
            val bottom = fontMetrics.bottom
            val baseLineY = rect?.centerY()?.let { it1 -> it1 - top / 2 - bottom / 2 }
            it.translate(rect?.centerX()?.toFloat() ?: 0f, baseLineY ?: 0f)
            for (i in 1..12) {
                canvas.drawText(
                    i.toString(),
                    (d * cos(Math.toRadians((60 - (i - 1) * 30).toDouble()))).toFloat(),
                    -(d * sin(Math.toRadians((60 - (i - 1) * 30).toDouble()))).toFloat(),
                    paint
                )
            }
            it.restore()
            it.save()

            //时针
            it.translate(width.toFloat() / 2, height.toFloat() / 2)//平移
            it.save()
            it.rotate(rotateHour)
            paint.strokeWidth = 4f.dp2px()
            it.drawLine(
                0f,
                4f.dp2px(),
                0f,
                -(mRadius / 2),
                paint
            )
            it.restore()
            it.save()
            //分针
            it.rotate(rotateMinute)
            paint.strokeWidth = 2f.dp2px()
            it.drawLine(
                0f,
                8f.dp2px(),
                0f,
                -(mRadius * 2 / 3),
                paint
            )
            it.restore()
            it.save()
            //秒针
            it.rotate(rotateSecond)
            paint.style = Paint.Style.FILL
            paint.strokeWidth = 1f.dp2px()
            paint.color = Color.RED
            it.drawLine(
                0f,
                16f.dp2px(),
                0f,
                -(mRadius - 8f.dp2px()),
                paint
            )
            it.restore()
            //针冒
            it.save()
            paint.style = Paint.Style.FILL
            paint.strokeWidth = paintWidth
            paint.color = Color.BLACK
            it.drawCircle(
                0f,
                0f,
                4f.dp2px(), paint
            )
            it.restore()

        }
    }

    private var rotateSecond = 0f
    private var rotateMinute = 0f
    private var rotateHour = 0f
    private var toUpdateUI = false

    override fun onVisibilityChanged(changedView: View, visibility: Int) {
        super.onVisibilityChanged(changedView, visibility)
        toUpdateUI = visibility == VISIBLE
    }

}


fun Float.dp2px(): Float {
    val scale = Resources.getSystem().displayMetrics.density
    return this.times(scale).plus(0.5).toFloat()
}

/**
 * 12小时制
 */
fun Date.getHour(): Int =
    Calendar.getInstance().apply { time = this@getHour }.get(Calendar.HOUR)

fun Date.getMinute(): Int =
    Calendar.getInstance().apply { time = this@getMinute }.get(Calendar.MINUTE)

fun Date.getSecond(): Int =
    Calendar.getInstance().apply { time = this@getSecond }.get(Calendar.SECOND)